﻿using System;
using System.Collections.Generic;
using BitButterCORE.Component;
using BitButterCORE.Factory;

namespace BitButterCORE.Object
{
	public abstract class BaseObject
	{
		public BaseObject()
		{
			Factory.AddObject(this);
			Reference = CreateReference();
		}

		public BaseObject(uint id)
		{
			if (id > 0)
			{
				this.id = id;
			}
		}

		public uint ID
		{
			get => id;
			set
			{
				if (!IsManaged && value > 0)
				{
					id = value;
				}
			}
		}

		uint id;

		public bool IsManaged => ID > 0;

		public IObjectReference<BaseObject> Reference { get; }

		protected abstract IObjectReference<BaseObject> CreateReference();

		protected abstract IFactory Factory { get; }

		public void AttachComponent(BaseComponent component)
		{
			var componentType = component.GetType();
			if (!Components.ContainsKey(componentType))
			{
				Components.Add(componentType, component);
			}
			else
			{
				// todo: some error reporting here
				// should not add two components with the exact same type
				// ...
			}
		}

		public virtual T GetComponent<T>()
			where T : BaseComponent
		{
			if (Components.ContainsKey(typeof(T)))
			{
				return Components[typeof(T)] as T;
			}
			return null;
		}

		public bool HasAllComponents(IEnumerable<Type> componentTypes)
		{
			foreach (Type componentType in componentTypes)
			{
				if (!Components.ContainsKey(componentType))
				{
					return false;
				}
			}
			return true;
		}

		protected Dictionary<Type, BaseComponent> Components => components ?? (components = new Dictionary<Type, BaseComponent>());
		Dictionary<Type, BaseComponent> components;

		public virtual byte[] Serialize()
		{
			return null;
		}

		public virtual void Deserialize(byte[] objectPayload)
		{
		}
	}
}
